//
//  Recorder.swift
//  Recorder
//
//  Created by 魏滨 on 2020/4/2.
//  Copyright © 2020 魏滨. All rights reserved.
//

import AVFoundation

class Recorder: NSObject {
    private static let BTimerKey = "RecorderTimerKey"
    static func start(_ path: String? = nil,duration: TimeInterval, isSave: Bool = true,  metersBlock: MetersBlock? =  nil, timerBlock: ((BTimerModel) -> Void)?, complete: RecorderCompleteBlock?, failure: RecorderFailureBlock?) {
        start(path, isSave: isSave, metersBlock: metersBlock, failure: failure)
        BTimer.start(timerName: BTimerKey, timeInterval: 1, totalTrigger: duration, queue: .main, block: timerBlock) {
            stop(complete, failure: failure)
        }
    }
    
    
    /// 开始录音
    /// - Parameters:
    ///   - path: 要存储的路径
    ///   - isSave: 是否保存
    ///   - failure: 失败错误信息
    static func start(_ path: String? = nil, isSave: Bool = true, metersBlock: MetersBlock? =  nil, failure: RecorderFailureBlock?) {
        shared.path = path
        shared.failure = failure
        guard let url = URL.init(string: filePath()) else {
            print("录音路径出错")
            failure?("录音路径出错")
            return
        }
        if shared.recorder == nil {
            do {
                shared.recorder = try AVAudioRecorder.init(url: url, settings: shared.recordSettings)
            } catch let error {
                print(error.localizedDescription)
                failure?(error.localizedDescription)
            }
        }

        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playAndRecord)
            try audioSession.setActive(true, options: AVAudioSession.SetActiveOptions.notifyOthersOnDeactivation)
        } catch {
            print(error.localizedDescription)
            failure?(error.localizedDescription)
        }
        
        shared.recorder?.delegate = shared
        if !isSave {
            shared.recorder?.deleteRecording()
        }
        if !shared.isRecording {
            shared.recorder?.record()
        }
        shared.metersBlock = metersBlock
        if metersBlock != nil {
            openMetersBlock()
        }
    }

    
    /// 结束录音
    /// - Parameters:
    ///   - complete: 录音完成(时长，路径)
    ///   - failure: 错误失败
    static func stop(_ complete: RecorderCompleteBlock?, failure: RecorderFailureBlock?) {
        shared.complete = complete
        shared.failure = failure
        if shared.metersBlock != nil {
            closeopenMeters()
        }
        if shared.isRecording {
            shared.recorder?.stop()
        }
        BTimer.cancel(timerName: BTimerKey)
    }
    
    /// 录音暂停
    static func pause() {
        if shared.isRecording {
            if shared.metersBlock != nil {
                closeopenMeters()
            }
            shared.recorder?.pause()
            BTimer.suspend(timerName: BTimerKey)
        }
    }
    
    /// 恢复录音
    static func record() {
        if !shared.isRecording {
            if shared.metersBlock != nil {
                openMetersBlock()
            }
            shared.recorder?.record()
            BTimer.resume(timerName: BTimerKey)
        }
    }
    
    /// 获取录音文件存储路径
    static func filePath() -> String {
        return shared.path ?? String.cachesPath + "/record.caf"
    }
    
    /// 开启分贝回调
    private static func openMetersBlock() {
        shared.recorder?.isMeteringEnabled = true
        shared.link = CADisplayLink.init(target: self, selector: #selector(displayLinkClick(_:)))
        shared.link?.add(to: .current, forMode: .default)
    }
    /// 关闭分贝
    private static func closeopenMeters() {
        shared.link?.invalidate()
        shared.link = nil
     }
    
    
    // MARK: - 隐私方法
    @objc private static func displayLinkClick(_ sender: CADisplayLink){
        shared.recorder?.updateMeters()
        var level = 0.0
        
        //获取分贝
        let peakPower: Float = shared.recorder?.peakPower(forChannel: 0) ?? 0
        
        //设置一个最低分贝
        let minDecibels: Float = -60
        
        if peakPower < minDecibels {
            level = 0.0
        }else if peakPower >= 0.0 {
            level = 1.0
        }else {
            let root            = 2.0;
            //最小分贝的波形幅度值 公式: db 分贝 A 波形幅度值   dB=20∗log(A)→A=pow(10,(db/20.0))
            let minAmp          = powf(10.0, 0.05 * minDecibels);
            let inverseAmpRange = 1.0 / (1.0 - minAmp);
            //实时获取到波形幅度值 公式同上
            let amp             = powf(10.0, 0.05 * peakPower);
            //(实时数据 - 最小数据)/(最大数据 - 最小数据)  应该计算的一个比例值吧
            let adjAmp          = (amp - minAmp) * inverseAmpRange;
            level = Double(powf(adjAmp, Float(1.0 / root)));
        }
        shared.metersBlock?(level)
    }
    
    
    typealias RecorderFailureBlock = (_ errMsg: String) -> Void
    typealias RecorderCompleteBlock = (_ duration: TimeInterval,_ path: String) -> Void
    typealias MetersBlock = (_ meter: Double) -> Void
    
    /// 失败回调
    private var failure: RecorderFailureBlock?
    /// 完成回调
    private var complete: RecorderCompleteBlock?
    /// 分贝回调
    private var metersBlock: MetersBlock?
    /// 是否暂停
    private var isRecording: Bool {
        return Recorder.shared.recorder?.isRecording ?? false
    }
    /// 单例
    private static let shared = Recorder()
    /// 录音器
    private var recorder: AVAudioRecorder?
    // 定时器
    private var link: CADisplayLink?
    /// 输惨过来的文件路径
    private var path: String?

    //创建字典，用于保存录制属性
    private let recordSettings:[String:Any] = [
        AVEncoderAudioQualityKey : AVAudioQuality.max.rawValue, // 录音质量
        AVNumberOfChannelsKey : 1,  // 采集音轨
        AVSampleRateKey : 16000, // 声音采样率
        AVFormatIDKey : kAudioFormatLinearPCM, // 编码格式
        AVLinearPCMIsFloatKey: true
        //  AVLinearPCMBitDepthKey : NSNumber(value: 32),            // 采样位数
        //  AVEncoderBitRateKey : NSNumber(value: 128000),           // 编码时的比特率，是每秒传送的比特(bit)数单位为bps(Bit Per Second)，比特率越高传送数据速度越快值是一个整数
    ]
    
}

extension Recorder: AVAudioRecorderDelegate {
    func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
        if flag {
            complete?(Recorder.getDuration(), Recorder.filePath())
        }else {
            failure?("录音失败")
        }
    }
    
    func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
        failure?(error?.localizedDescription ?? "录音失败")
    }

}


extension Recorder {
    /// 播放录制文件
    ///
    /// - Parameter compelete: 播放完毕回调
    static func play() {
        do {
            try AVAudioSession.sharedInstance().setCategory(.playback)
        } catch let error {
            NSLog(error.localizedDescription)
            return
        }
        if !FileManager.default.fileExists(atPath: filePath()) {
            print("未录制，或录制的文件不存在")
            return
        }
        
        guard let url = URL.init(string: filePath()) else {
            print("播放地址解析错误")
            return }
        do {
            let  player = try AVAudioPlayer.init(contentsOf: url)
            player.play()
        } catch let error {
            print(error.localizedDescription)
        }
    }
    
    private static func getDuration() -> TimeInterval {
        var duration: TimeInterval = 0
        do {
            if let url = URL.init(string: Recorder.filePath()) {
                let player = try AVAudioPlayer.init(contentsOf: url)
                duration = player.duration
            }
        } catch {
            duration = 0
        }
        return duration
    }
    
}
